package cn.com.header.zbpk.web.security;

import cn.com.header.zbpk.account.entity.Authority;
import cn.com.header.zbpk.account.service.IAuthorityService;
import cn.com.header.zbpk.model.AuthorityMode;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 加载权限资源配置
 *
 * @author liangzhongqiu
 * @date 2017-09-13
 * @time 14:01
 **/
public class DatabaseFilterInvocationSecurityMetadataSource extends DefaultFilterInvocationSecurityMetadataSource implements InitializingBean {

    private final IAuthorityService iAuthorityService;

    private static LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = Maps.newLinkedHashMapWithExpectedSize(128);

    /**
     * 只要是登录用户，均可访问的地址
     */
    private Set<String> excludeUrls;

    @Autowired
    public DatabaseFilterInvocationSecurityMetadataSource(IAuthorityService iAuthorityService) {
        super(map);
        this.iAuthorityService = iAuthorityService;
    }
    @Override
    public void afterPropertiesSet() throws Exception {//初始化，将权限一次性加载
       /* if (Objects.nonNull(excludeUrls) && !excludeUrls.isEmpty()) {
            for (String url : excludeUrls) {
                map.put(new AntPathRequestMatcher(url), SecurityConfig.createList(Authority.ALL_AUTH));
            }
        }*/
        Authority authoritySelectModel = new Authority();
        authoritySelectModel.setMode(AuthorityMode.INTERCEPTOR);
        Set<Authority> authorities = iAuthorityService.queryAuthorityListByTemplate(authoritySelectModel, Sets.newHashSet("id", "assets"), null, null);
        if(Objects.nonNull(excludeUrls) && !excludeUrls.isEmpty()){
            Authority commonAuthority = new Authority();
            commonAuthority.setId(Authority.COMMON_AUTH_ACCESS_ID);
            commonAuthority.setAssets(excludeUrls);
            authorities.add(commonAuthority);
        }
        int length = authorities.size();
        Map<String, Set<String>> urlsWithAuthId = Maps.newLinkedHashMapWithExpectedSize(length * 2);
        for (Authority authority : authorities) {
            String id = authority.getId();
            for (String url : authority.getAssets()) {
                if (urlsWithAuthId.containsKey(url)) {
                    urlsWithAuthId.get(url).add(id);
                } else {
                    urlsWithAuthId.put(url, Sets.newHashSet(id));
                }
            }
        }
        for (Map.Entry<String, Set<String>> entry : urlsWithAuthId.entrySet()) {
            Set<String> values = entry.getValue();
            map.put(new AntPathRequestMatcher(entry.getKey()), SecurityConfig.createList(values.toArray(new String[values.size()])));
        }


    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        //缓存请求地址吻合的权限
        List<ConfigAttribute> configAttributes = Lists.newArrayListWithExpectedSize(16);
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : map
                .entrySet()) {
            if (entry.getKey().matches(request)) {
                configAttributes.addAll(entry.getValue());
            }
        }
        return configAttributes;
    }

    public void setExcludeUrls(Set<String> excludeUrls) {
        this.excludeUrls = excludeUrls;
    }

}
